﻿using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using BrightIdeasSoftware;
using PictureOrganizer2.DataContainer;
using PictureOrganizer2.Properties;
using System.Diagnostics;
using System.Text;
using PictureOrganizer2.Database;

namespace PictureOrganizer2.Forms
{
    public partial class ComicForm : Form
    {
        private log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public ComicForm()
        {
            InitializeComponent();
        }

        public ComicForm(int comicId)
            : this()
        {
            this.comicAdapter.FillByID(this.dbSet.Comic, comicId);
            this.authorAdapter.Fill(this.dbSet.Author);
            this.pictureAdapter.FillByComicID(this.dbSet.Picture, comicId);
            this.tagAdapter.Fill(this.dbSet.Tag);
            this.comicHasTagAdapter.FillByComicId(dbSet.ComicHasTag, dbSet.Comic[0].ID);
            SetTags();

            // Prüfen, ob das Comic im Filesystem noch existiert.
            if (Directory.Exists(Path.Combine(dbSet.Comic[0].FolderPath, dbSet.Comic[0].FolderName)))
            {
                // Ordner existiert, also kann auch der Status aktualisiert werden.
                dbSet.Comic[0].FolderExists = true;
                dbSet.Comic[0].LastExistsCheck = DateTime.Now;
                SaveComic();
            }
            else
            {
                dbSet.Comic[0].FolderExists = false;
                dbSet.Comic[0].LastExistsCheck = DateTime.Now;
                SaveComic();
                // TODO Formular sperren.
            }

            this.dbSet.Comic.ColumnChanged += new System.Data.DataColumnChangeEventHandler(Comic_ColumnChanging);

            // BindingSource für Rating-Combobox mit Daten füllen
            foreach (var item in RatingContainer.GetRatingCollection())
            {
                this.ratingSource.Add(item);
            }

            // DisplayImage laden, nur wenn der Ordner existiert.
            if (dbSet.Comic[0].FolderExists)
            {
                // ObjectListView bestücken
                this.olvColumn1.ImageGetter = new ImageGetterDelegate(ColumnImageGetter);
                this.dataListView.View = View.LargeIcon;

                SetThumbnail(this.dbSet.Comic[0].DisplayImageID);
            }
            else
            {
                // Damit keine Bilder angezeigt werden, werden die Spalten entfernt.
                this.dataListView.Columns.Clear();

                this.dataListView.OverlayText.Alignment = System.Drawing.ContentAlignment.MiddleCenter;
                this.dataListView.OverlayText.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(128)))));
                this.dataListView.OverlayText.BorderColor = System.Drawing.Color.Red;
                this.dataListView.OverlayText.BorderWidth = 2F;
                this.dataListView.OverlayText.Text = "Das Comic wurde nicht gefunden!";
            }

            this.Text = String.Format("Comic: {0} ({1} Bilder)", this.dbSet.Comic[0].ComicName, this.dbSet.Picture.Count);
        }

        private void SetTags()
        {
            StringBuilder str = new StringBuilder();

            foreach (var item in dbSet.ComicHasTag)
            {
                var tag = (from t in dbSet.Tag where t.ID == item.TagID select t).First();
                str.AppendFormat("{0}, ", tag.Name);
            }

            this.tb_Tags.Text = str.ToString().TrimEnd(',', ' ');
        }

        #region Interne Funktionen
        private void SetThumbnail(int pictureId)
        {
            string basePath = Path.Combine(dbSet.Comic[0].FolderPath, dbSet.Comic[0].FolderName);
            string pictureFileName = (from row in dbSet.Picture where row.ID == pictureId select row.FileName).First();
            string fileName = Path.Combine(basePath, pictureFileName);

            using (FileStream s = File.OpenRead(fileName))
            {
                this.pictureBox.Image = Image.FromStream(s);
            }
        }

        private void ComicForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
            {
                this.Close();
            }
        }

        private void ComicForm_Load(object sender, EventArgs e)
        {
            if (dbSet.Comic[0].FolderExists)
            {
                backgroundWorker_LoadImages.RunWorkerAsync();
            }
        }

        private void ComicForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.dbSet.Comic.Count == 0) return;
            this.dbSet.Comic[0].EndEdit();

            if (this.dbSet.Comic[0].RowState == DataRowState.Modified)
            {
                DialogResult dr = MessageBox.Show("Es sind noch nicht gespeicherte Änderungen offen. Sollen diese jetzt gespeichert werden?", "Warnung", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3);
                if (dr == DialogResult.Yes)
                {
                    SaveComic();
                }
                else if (dr == DialogResult.Cancel)
                {
                    e.Cancel = true;
                }
            }
            if (!e.Cancel)
            {
                if (this.backgroundWorker_LoadImages.IsBusy)
                {
                    this.backgroundWorker_LoadImages.CancelAsync();
                }
            }
        }
        #endregion

        #region ToolStrip

        #region Button Close
        private void tsb_Close_Click(object sender, EventArgs e)
        {
            this.Close();
        }
        #endregion

        #region Button Save
        private void tsb_Save_Click(object sender, EventArgs e)
        {
            SaveComic();
            // Speicherbutton nach erfolgreichen Speichern wieder sperren
            this.tsb_Save.Enabled = false;
        }

        private void SaveComic()
        {
            // Das hier MUSS aufgerufen werden, damit der RowStat korrekt auf 
            // "Modified" gesetzt wird und somit überhaupt erst das Update klappt
            this.dbSet.Comic[0].EndEdit();
            if (Utility.hasCellChanged(this.dbSet.Comic[0], dbSet.Comic.FolderNameColumn))
            {
                // Ordner wird umbenannt
                string rootPath = this.dbSet.Comic[0].FolderPath;
                string oldFolderPath = Path.Combine(rootPath, (string)this.dbSet.Comic[0][dbSet.Comic.FolderNameColumn, DataRowVersion.Original]);
                string newFolderPath = Path.Combine(rootPath, this.dbSet.Comic[0].FolderName);
                Directory.Move(oldFolderPath, newFolderPath);
            }
            if (dbSet.Comic[0].RowState == DataRowState.Modified)
            {
                this.comicAdapter.Update(this.dbSet.Comic);
            }

            this.tsb_Save.Enabled = false;
        }
        #endregion

        #endregion

        #region ComicForm

        private void tb_ComicName_Validating(object sender, CancelEventArgs e)
        {
            string t = this.tb_ComicName.Text;
            if (string.IsNullOrWhiteSpace(t))
            {
                this.errorProvider.SetError(this.tb_ComicName, "Der Comicname darf nicht leer sein.");
                this.tb_ComicName.Undo();
            }
        }

        private void btn_AddAuthor_Click(object sender, EventArgs e)
        {
            using (AddAuthorForm dlg = new AddAuthorForm())
            {
                if (dlg.ShowDialog(this) == DialogResult.OK)
                {
                    this.authorAdapter.Fill(this.dbSet.Author);
                    this.dbSet.Comic[0].AuthorID = dlg.AuthorId;
                }
            }
        }

        public bool ThumbnailCallback()
        {
            return false;
        }
        public Image GetThumbnail(string fileName, int width, int height)
        {
            Image i;
            using (FileStream s = File.OpenRead(fileName))
            {
                i = Image.FromStream(s).GetThumbnailImage(width, height, new Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
            }
            return i;
        }

        void Comic_ColumnChanging(object sender, System.Data.DataColumnChangeEventArgs e)
        {
            PictureOrganizer2.Database.DatabaseDataSet.ComicRow row = this.dbSet.Comic[0];
            string newFolderName = String.Format(
                "{0}{1} {2}{3}{4}{5}",
                row[dbSet.Comic.AuthorIDColumn] != DBNull.Value ? "[" + row.AuthorRow.AuthorName + "] " : "",
                row.ComicName,
                row.IsColored ? "[col]" : "",
                row.IsUncensored ? "[uncensored]" : "",
                row.IsRescan ? "[rescan]" : "",
                !string.IsNullOrWhiteSpace(row[dbSet.Comic.LanguageColumn] != DBNull.Value ? row.Language : "") ? "[" + row.Language + "]" : "").Trim();

            if (!row.FolderName.Equals(newFolderName))
                this.tb_FolderName.Text = newFolderName;

            if (dbSet.Comic[0].IsRead && (dbSet.Comic[0].IsReadDateNull() || dbSet.Comic[0].ReadDate == DateTime.MinValue))
            {
                dbSet.Comic[0].ReadDate = DateTime.Now;
            }
            else if (!dbSet.Comic[0].IsRead && !dbSet.Comic[0].IsReadDateNull() && dbSet.Comic[0].ReadDate.CompareTo(DateTime.MinValue) != 0)
            {
                dbSet.Comic[0].SetReadDateNull();
            }

            this.tsb_Save.Enabled = true;
        }

        #endregion

        #region ListView

        #region Initiale Bildbestückung mit Default-Image

        delegate void AddImageListItemCallback(ImageList imagelist, string imageKey, Image image);
        private void AddImageListItemReal(ImageList imagelist, string imageKey, Image image)
        {
            imagelist.Images.Add(imageKey, image);
        }
        private void AddImageListItem(ImageList imagelist, string imageKey, Image image)
        {
            try
            {
                if (this.InvokeRequired)
                {
                    AddImageListItemCallback d = new AddImageListItemCallback(AddImageListItemReal);
                    this.Invoke(d, new object[] { imagelist, imageKey, image });
                }
                else
                {
                    AddImageListItemReal(imageList, imageKey, image);
                }
            }
            catch (ObjectDisposedException ex)
            {
                logger.Warn("Das aktualisieren des Forms ist gescheitet, da es bereits gelöscht wurde.", ex);
            }
        }

        object ColumnImageGetter(object rowObject)
        {
            DataRowView row = (DataRowView)rowObject;
            string imageKey = (string)row[dbSet.Picture.FileNameColumn.ColumnName];

            AddImageListItem(imageList, imageKey, Images.defaultImage);

            return imageKey;
        }
        #endregion

        #region Laden der realen Bilder
        private void backgroundWorker_LoadImages_DoWork(object sender, DoWorkEventArgs e)
        {
            string basePath = Path.Combine(dbSet.Comic[0].FolderPath, dbSet.Comic[0].FolderName);

            foreach (var item in this.dbSet.Picture)
            {
                if (this.backgroundWorker_LoadImages.CancellationPending) return;
                string imageKey = item.FileName;

                ClearImageList(imageKey);
                AddImage(imageKey, GetThumbnail(Path.Combine(basePath, item.FileName), 128, 128));
            }
        }

        private delegate void ClearImageListDelegate(string key);
        private void ClearImageList(string key)
        {
            if (this.InvokeRequired)
            {
                ClearImageListDelegate d = new ClearImageListDelegate(ClearImageList);
                try
                {
                    this.Invoke(d, key);
                }
                catch (Exception ex)
                {
                    logger.Warn("Das aktualisieren des Forms ist gescheitet, da es bereits gelöscht wurde.", ex);
                }
            }
            else
            {
                this.imageList.Images.RemoveByKey(key);
            }
        }

        private delegate void AddImageDelegate(string key, Image image);
        private void AddImage(string key, Image image)
        {
            if (this.InvokeRequired)
            {
                AddImageDelegate d = new AddImageDelegate(AddImage);
                try
                {
                    this.Invoke(d, key, image);
                }
                catch (Exception ex)
                {
                    logger.Warn("Das aktualisieren des Forms ist gescheitet, da es bereits gelöscht wurde.", ex);
                }
            }
            else
            {
                this.imageList.Images.Add(key, image);
            }
        }


        #endregion

        private void objectListView_DoubleClick(object sender, EventArgs e)
        {
            if (dataListView.SelectedObject != null)
            {
                string fileName = Path.Combine(
                    dbSet.Comic[0][dbSet.Comic.FolderPathColumn.ColumnName].ToString(),
                    dbSet.Comic[0][dbSet.Comic.FolderNameColumn.ColumnName].ToString(),
                    ((DataRowView)dataListView.SelectedObject)[dbSet.Picture.FileNameColumn.ColumnName].ToString());

                Process.Start(fileName);

            }
        }
        #endregion

        #region ContextMenuStrip ListView
        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            if (this.dataListView.SelectedObject != null && (int)((DataRowView)this.dataListView.SelectedObject)[dbSet.Picture.IDColumn.ColumnName] != (int)this.dbSet.Comic[0].DisplayImageID)
            {
                this.tsmi_SetAsThumbnail.Enabled = true;
            }
            else
            {
                this.tsmi_SetAsThumbnail.Enabled = false;
            }
        }

        #region Button SetAsThumbnail
        private void tsmi_SetAsThumbnail_Click(object sender, EventArgs e)
        {
            if (this.dataListView.SelectedObject != null)
            {
                this.dbSet.Comic[0].DisplayImageID = (int)((DataRowView)this.dataListView.SelectedObject)[dbSet.Picture.IDColumn.ColumnName];
                SetThumbnail(this.dbSet.Comic[0].DisplayImageID);
            }
        }
        #endregion

        private void btn_EditTags_Click(object sender, EventArgs e)
        {
            using (var dlg = new EditComicTagsForm(dbSet.Comic[0].ID))
            {
                if (dlg.ShowDialog(this) == DialogResult.OK)
                {
                    this.comicHasTagAdapter.FillByComicId(dbSet.ComicHasTag, dbSet.Comic[0].ID);
                }
            }

            this.comicHasTagAdapter.FillByComicId(this.dbSet.ComicHasTag, this.dbSet.Comic[0].ID);
            SetTags();
        }

        #endregion

    }
}
